//
//  FormView.m
//  etionUI
//
//  Created by wangjian on 12/23/13.
//  Copyright (c) 2013 GuangZhouXuanWu. All rights reserved.
//

#import "FormView.h"

#define DEF_REUSE_IDENTIFIER @"CFORM_CELL_DEF_REUSE_IDENTIFIER"

//@interface UIScrollView (FormView)
//
//@end
//
//@implementation UIScrollView (FormView)
//
//- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//{
//    if (!self.dragging)
//    {
//        [[self nextResponder] touchesBegan:touches withEvent:event];
//    }
//    else
//    {
//        [super touchesBegan:touches withEvent:event];
//    }
//}
//
//- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
//{
//    if (!self.dragging)
//    {
//        [self.nextResponder touchesMoved:touches withEvent:event];
//    }
//    else
//    {
//        [super touchesMoved:touches withEvent:event];
//    }
//}
//
//- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
//{
//    if (self.dragging)
//    {
//        [[self nextResponder] touchesCancelled:touches withEvent:event];
//    }
//    else
//    {
//        [super touchesCancelled:touches withEvent:event];
//    }
//}
//
//- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
//{
//    if (!self.dragging)
//    {
//        [[self nextResponder] touchesEnded:touches withEvent:event];
//    }
//    else
//    {
//        [super touchesEnded:touches withEvent:event];
//    }
//}
//
//@end


/**
 *  CFormView
 */

@interface CFormView()

@property (nonatomic, retain) NSMutableArray *arRowHeight;  //记录每一行的高度
@property (nonatomic, retain) NSMutableArray *arColWidth;   //记录每一列的宽度
@property (nonatomic, retain) NSMutableArray *arRowStartY;  //记录每一行的起始位置的Y值，会多记录一行，方便计算
@property (nonatomic, retain) NSMutableArray *arColStartX;  //记录每一列的起始位置的X值，会多记录一列，方便计算

@property (nonatomic, retain) CFormCellIndex *curLeftTopIndex;
@property (nonatomic, retain) CFormCellIndex *curRightBottomIndex;
@property (nonatomic, retain) CFormCellIndex *curHighlightIndex;

@property (nonatomic, retain) NSMutableArray *arCellViews;  //所有的cell，不可见的cell为[NSNull null]
@property (nonatomic, retain) NSMutableDictionary *dicReuseCellViews;   //重用池

@end

@implementation CFormView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.opaque = NO;
        self.arCellViews = [NSMutableArray array];
        self.dicReuseCellViews = [NSMutableDictionary dictionary];
        self.arRowHeight = [NSMutableArray array];
        self.arColWidth = [NSMutableArray array];
        self.arRowStartY = [NSMutableArray array];
        self.arColStartX = [NSMutableArray array];
        self.curLeftTopIndex = [CFormCellIndex indexWithtRow:0 col:0];
        self.curRightBottomIndex = [CFormCellIndex indexWithtRow:0 col:0];
        self.showsHorizontalScrollIndicator = NO;
        self.showsVerticalScrollIndicator = NO;
    }
    return self;
}

- (void)didMoveToSuperview
{
    [super didMoveToSuperview];
    if (self.superview != nil)
    {
        [self reload];
    }
}

- (void)setContentOffset:(CGPoint)contentOffset
{
    [super setContentOffset:contentOffset];
    if (self.rowNumber > 0 && self.colNumber > 0)
    {
        [self loadVisibleCells];
    }
}

#pragma mark - inner method

- (CFormCellIndex *)pointToIndex:(CGPoint)point
{
    point.x += self.contentOffset.x;
    point.y += self.contentOffset.y;
    
    NSUInteger row=0, col=0;
    for (row = 0; row < self.rowNumber; row++)
    {
        if (point.y < [[self.arRowStartY objectAtIndex:row+1] floatValue])
        {
            break;
        }
    }
    if (row >= self.rowNumber)
    {
        row = self.rowNumber-1;
    }
    for (col = 0; col < self.colNumber; col++)
    {
        if (point.x < [[self.arColStartX objectAtIndex:col+1] floatValue])
        {
            break;
        }
    }
    if (col >= self.colNumber)
    {
        col = self.colNumber-1;
    }
    return [CFormCellIndex indexWithtRow:row col:col];
}

- (CGRect)cellFrameOfIndex:(CFormCellIndex *)index
{
    return CGRectMake([[self.arColStartX objectAtIndex:index.col] floatValue], [[self.arRowStartY objectAtIndex:index.row] floatValue], [[self.arColWidth objectAtIndex:index.col] floatValue], [[self.arRowHeight objectAtIndex:index.row] floatValue]);
}

#pragma mark - load view

- (void)prepareReload
{
    //清除之前的cell
    for (NSArray *arCells in self.arCellViews)
    {
        for (id cell in arCells)
        {
            if ([cell isKindOfClass:[CFormCellView class]])
            {
                [cell removeFromSuperview];
            }
        }
    }
    [self.arCellViews removeAllObjects];
    [self.dicReuseCellViews removeAllObjects];
    self.rowNumber = [self.delegate numberOfRowsWithFormView:self];
    self.colNumber = [self.delegate numberOfColsWithFormView:self];
    for (NSUInteger row=0; row<self.rowNumber; row++)
    {
        NSMutableArray *arCells = [NSMutableArray array];
        [self.arCellViews addObject:arCells];
        
        for (NSUInteger col=0; col<self.colNumber; col++)
        {
            [arCells addObject:[NSNull null]];
        }
    }
    
    [self.arRowHeight removeAllObjects];
    [self.arColWidth removeAllObjects];
    [self.arRowStartY removeAllObjects];
    [self.arColStartX removeAllObjects];
    CGFloat curRowStartY = 0;
    if ([self.delegate respondsToSelector:@selector(formView:heightForRow:)])
    {
        for (NSUInteger row=0; row<self.rowNumber; row++)
        {
            CGFloat rowH = [self.delegate formView:self heightForRow:row];
            [self.arRowHeight addObject:[NSNumber numberWithFloat:rowH]];
            [self.arRowStartY addObject:[NSNumber numberWithFloat:curRowStartY]];
            curRowStartY += rowH;
        }
    }
    else
    {
        for (NSUInteger row=0; row<self.rowNumber; row++)
        {
            [self.arRowHeight addObject:[NSNumber numberWithFloat:FORMVIEW_DEF_ROW_H]];
            [self.arRowStartY addObject:[NSNumber numberWithFloat:curRowStartY]];
            curRowStartY += FORMVIEW_DEF_ROW_H;
        }
    }
    [self.arRowStartY addObject:[NSNumber numberWithFloat:curRowStartY]];
    
    CGFloat curColStartX = 0;
    if ([self.delegate respondsToSelector:@selector(formView:widthForCol:)])
    {
        for (NSUInteger col=0; col<self.colNumber; col++)
        {
            CGFloat colW = [self.delegate formView:self widthForCol:col];
            [self.arColWidth addObject:[NSNumber numberWithFloat:colW]];
            [self.arColStartX addObject:[NSNumber numberWithFloat:curColStartX]];
            curColStartX += colW;
        }
    }
    else
    {
        for (NSUInteger col=0; col<self.colNumber; col++)
        {
            [self.arColWidth addObject:[NSNumber numberWithFloat:FORMVIEW_DEF_COL_W]];
            [self.arColStartX addObject:[NSNumber numberWithFloat:curColStartX]];
            curColStartX += FORMVIEW_DEF_COL_W;
        }
    }
    [self.arColStartX addObject:[NSNumber numberWithFloat:curColStartX]];
    
    self.curLeftTopIndex.row = 0;
    self.curLeftTopIndex.col = 0;
    self.curRightBottomIndex.row = 0;
    self.curRightBottomIndex.col = 0;
}

- (void)loadVisibleCells
{
    CFormCellIndex *leftTopIndex = [self pointToIndex:CGPointMake(0, 0)];
    CFormCellIndex *rightBottomIndex = [self pointToIndex:CGPointMake(self.width, self.height)];
    
    //回收不用再显示的cell
    for (NSUInteger row=self.curLeftTopIndex.row; row<=self.curRightBottomIndex.row; row++)
    {
        NSMutableArray *arCells = [self.arCellViews objectAtIndex:row];
        for (NSUInteger col=self.curLeftTopIndex.col; col<=self.curRightBottomIndex.col; col++)
        {
            if (row<leftTopIndex.row || row>rightBottomIndex.row || col<leftTopIndex.col || col>rightBottomIndex.col)
            {
                id cell = [arCells objectAtIndex:col];
                if ([cell isKindOfClass:[CFormCellView class]])
                {
                    [self addCellToReuseDictionary:cell];
                    [cell removeFromSuperview];
                    [arCells replaceObjectAtIndex:col withObject:[NSNull null]];
                }
            }
        }
    }
    
    //加载需要显示的cell
    self.curLeftTopIndex = leftTopIndex;
    self.curRightBottomIndex = rightBottomIndex;
    for (NSUInteger row=self.curLeftTopIndex.row; row<=self.curRightBottomIndex.row; row++)
    {
        NSMutableArray *arCells = [self.arCellViews objectAtIndex:row];
        for (NSUInteger col=self.curLeftTopIndex.col; col<=self.curRightBottomIndex.col; col++)
        {
            id cell = [arCells objectAtIndex:col];
            if (![cell isKindOfClass:[CFormCellView class]])
            {
                CFormCellIndex *index = [CFormCellIndex indexWithtRow:row col:col];
                CFormCellView *newCell = [self.delegate formView:self cellAtIndex:index];
                if (newCell != nil)
                {
                    newCell.selected = [self.curSelectedIndex isEqualToIndex:index];
                    [arCells replaceObjectAtIndex:col withObject:newCell];
                    newCell.frame = [self cellFrameOfIndex:index];
                    [self addSubview:newCell];
                }
            }
        }
    }
}

- (void)reload
{
    [self prepareReload];
    
    self.contentSize = CGSizeMake([[self.arColStartX lastObject] floatValue], [[self.arRowStartY lastObject] floatValue]);
    
    if (self.rowNumber > 0 && self.colNumber > 0)
    {
        [self loadVisibleCells];
    }
}

# pragma mark - reuse cell

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
{
    id cell = nil;
    if (identifier.length == 0)
    {
        identifier = DEF_REUSE_IDENTIFIER;
    }
    NSMutableArray *arReuseCells = [self.dicReuseCellViews objectForKey:identifier];
    if (arReuseCells.count > 0)
    {
        cell = [[[arReuseCells lastObject] retain] autorelease];
        [arReuseCells removeLastObject];
    }
    return cell;
}

- (void)addCellToReuseDictionary:(CFormCellView *)cell
{
    NSString *reuseIdentifier = cell.reuseIdentifier;
    if (reuseIdentifier.length == 0)
    {
        reuseIdentifier = DEF_REUSE_IDENTIFIER;
    }
    NSMutableArray *arReuseCells = [self.dicReuseCellViews objectForKey:reuseIdentifier];
    if (arReuseCells == nil)
    {
        arReuseCells = [NSMutableArray array];
        [self.dicReuseCellViews setObject:arReuseCells forKey:reuseIdentifier];
    }
    [arReuseCells addObject:cell];
}

#pragma mark - user interface

- (CFormCellView *)cellAtIndex:(CFormCellIndex *)index
{
    id cell = [[self.arCellViews objectAtIndex:index.row] objectAtIndex:index.col];
    if ([cell isKindOfClass:[CFormCellView class]])
    {
        return cell;
    }
    return nil;
}

- (CFormCellIndex *)indexForCell:(CFormCellView *)cell
{
    for (NSUInteger row=0; row<self.rowNumber; row++)
    {
        NSArray *arCells = [self.arCellViews objectAtIndex:row];
        NSUInteger col = [arCells indexOfObject:cell];
        if (col != NSNotFound)
        {
            return [CFormCellIndex indexWithtRow:row col:col];
        }
    }
    return nil;
}

- (CGRect)frameOfCellAtIndex:(CFormCellIndex *)index
{
    CGRect cellFrame = CGRectMake([[self.arColStartX objectAtIndex:index.col] floatValue],
                                  [[self.arRowStartY objectAtIndex:index.row] floatValue],
                                  [[self.arColWidth objectAtIndex:index.col] floatValue],
                                  [[self.arRowHeight objectAtIndex:index.row] floatValue]);
    return cellFrame;
}

- (void)scrollToIndex:(CFormCellIndex *)index animated:(BOOL)animated
{
    CGRect cellFrame = [self frameOfCellAtIndex:index];
    CGFloat moreOffsetY = 0;
    if (self.height <= cellFrame.size.height)
    {
        moreOffsetY = 0;
    }
    else if (self.height <= cellFrame.size.height+80)
    {
        moreOffsetY = (self.height-cellFrame.size.height)/2;
    }
    else
    {
        moreOffsetY = 40;
    }
    [self scrollRectToVisible:CGRectInset([self frameOfCellAtIndex:index], -40, -moreOffsetY) animated:animated];
}

- (CGFloat)heightForRow:(NSUInteger)row
{
    return [[self.arRowHeight objectAtIndex:row] floatValue];
}

- (CGFloat)widthForCol:(NSUInteger)col
{
    return [[self.arColWidth objectAtIndex:col] floatValue];
}

- (void)setHeight:(CGFloat)height forRow:(NSUInteger)row animated:(BOOL)animated
{
    [self.arRowHeight replaceObjectAtIndex:row withObject:[NSNumber numberWithFloat:height]];
    CGFloat curStartY = [[self.arRowStartY objectAtIndex:row] floatValue];
    for (NSUInteger i=row; i<self.rowNumber; i++)
    {
        [self.arRowStartY replaceObjectAtIndex:i withObject:[NSNumber numberWithFloat:curStartY]];
        curStartY += [[self.arRowHeight objectAtIndex:i] floatValue];
    }
    [self.arRowStartY replaceObjectAtIndex:self.rowNumber withObject:[NSNumber numberWithFloat:curStartY]];
    self.contentSize = CGSizeMake(self.contentSize.width, curStartY);
    void(^fun)() = ^()
    {
        for (NSUInteger curRow=MAX(self.curLeftTopIndex.row, row); curRow<=self.curRightBottomIndex.row; curRow++)
        {
            NSMutableArray *arCells = [self.arCellViews objectAtIndex:curRow];
            for (NSUInteger col=self.curLeftTopIndex.col; col<=self.curRightBottomIndex.col; col++)
            {
                id cell = [arCells objectAtIndex:col];
                if ([cell isKindOfClass:[CFormCellView class]])
                {
                    CFormCellView *cellView = cell;
                    cellView.frame = CGRectMake(cellView.left, [[self.arRowStartY objectAtIndex:curRow] floatValue], cellView.width, [[self.arRowHeight objectAtIndex:curRow] floatValue]);
                }
            }
        }
    };
    
    if (animated == NO)
    {
        fun();
        [self loadVisibleCells];
    }
    else
    {
        [UIView animateWithDuration:.25 animations:^{
            fun();
        } completion:^(BOOL finished) {
            [self loadVisibleCells];
        }];
    }
}

- (void)setWidth:(CGFloat)width forCol:(NSUInteger)col animated:(BOOL)animated
{
    [self.arColWidth replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:width]];
    CGFloat curStartX = [[self.arColStartX objectAtIndex:col] floatValue];
    for (NSUInteger i=col; i<self.colNumber; i++)
    {
        [self.arColStartX replaceObjectAtIndex:i withObject:[NSNumber numberWithFloat:curStartX]];
        curStartX += [[self.arColWidth objectAtIndex:i] floatValue];
    }
    [self.arColStartX replaceObjectAtIndex:self.colNumber withObject:[NSNumber numberWithFloat:curStartX]];
    self.contentSize = CGSizeMake(curStartX, self.contentSize.height);
    
    void(^fun)() = ^()
    {
        for (NSUInteger curRow=self.curLeftTopIndex.row; curRow<=self.curRightBottomIndex.row; curRow++)
        {
            NSMutableArray *arCells = [self.arCellViews objectAtIndex:curRow];
            for (NSUInteger curCol=MAX(self.curLeftTopIndex.col, col); curCol<=self.curRightBottomIndex.col; curCol++)
            {
                id cell = [arCells objectAtIndex:curCol];
                if ([cell isKindOfClass:[CFormCellView class]])
                {
                    CFormCellView *cellView = cell;
                    cellView.frame = CGRectMake([[self.arColStartX objectAtIndex:curCol] floatValue], cellView.top, [[self.arColWidth objectAtIndex:curCol] floatValue], cellView.height);
                }
            }
        }
    };
    
    if (animated == NO)
    {
        fun();
        [self loadVisibleCells];
    }
    else
    {
        [UIView animateWithDuration:.25 animations:^{
            fun();
        } completion:^(BOOL finished) {
            [self loadVisibleCells];
        }];
    }
}

#pragma mark - touch recognizer

- (void)setCurSelectedIndex:(CFormCellIndex *)curSelectedIndex
{
    if (_curSelectedIndex != nil && [curSelectedIndex isEqualToIndex:_curSelectedIndex])
    {
        return;
    }
    if (_curSelectedIndex != nil)
    {
        [[self cellAtIndex:_curSelectedIndex] setSelected:NO];
    }
    
    CFormCellIndex *tmp = [curSelectedIndex retain];
    [_curSelectedIndex release];
    _curSelectedIndex = tmp;
    
    if (_curSelectedIndex != nil)
    {
        [[self cellAtIndex:_curSelectedIndex] setSelected:YES];
    }
}

- (void)cancelTouchSelect
{
    if (self.curHighlightIndex != nil)
    {
        [[self cellAtIndex:self.curHighlightIndex] setSelectedState:NO animated:YES];
        self.curHighlightIndex = nil;
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint tapPoint = [touch locationInView:self];
    tapPoint.x -= self.contentOffset.x;
    tapPoint.y -= self.contentOffset.y;
    
    CFormCellIndex *index = [self pointToIndex:tapPoint];
    CFormCellView *cell = [self cellAtIndex:index];
    if (cell != nil && cell.selectable == YES)
    {
        self.curHighlightIndex = index;
        [cell setSelectedState:YES animated:YES];
    }
    else
    {
        if (self.curSelectedIndex != nil)
        {
            [self cellAtIndex:self.curSelectedIndex].selected = NO;
            self.curSelectedIndex = nil;
        }
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self cancelTouchSelect];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self cancelTouchSelect];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (self.curHighlightIndex != nil)
    {
//        if (self.curSelectedIndex != nil && (self.curSelectedIndex.row!=self.curHighlightIndex.row || self.curSelectedIndex.col!=self.curHighlightIndex.col))
//        {
//            
//        }
        [[self cellAtIndex:self.curHighlightIndex] setSelectedState:NO animated:YES];
        self.curSelectedIndex = self.curHighlightIndex;
        self.curHighlightIndex = nil;
        if ([self.delegate respondsToSelector:@selector(formView:didClickCellAtIndex:)])
        {
            [self.delegate formView:self didClickCellAtIndex:self.curSelectedIndex];
        }
    }
}

- (void)dealloc
{
    [_curSelectedIndex release];
    
    [_arRowHeight release];
    [_arColWidth release];
    [_arRowStartY release];
    [_arColStartX release];
    
    [_curLeftTopIndex release];
    [_curRightBottomIndex release];
    [_curHighlightIndex release];
    
    [_arCellViews release];
    [_dicReuseCellViews release];
    
    [super dealloc];
}

@end
